/** 计算宽高 */
const setSize = (imgWidth, imgHeight, defineWidth, defineHeight) => {
    const result = {
        width: 1,
        height: 1
    };
    const imgRatio = imgWidth / imgHeight;
    const defineRatio = defineWidth / defineHeight;
    /* 图片的宽高都小于 屏幕的宽高。取图片的宽高 */
    if (imgWidth <= defineWidth && imgHeight <= defineHeight) {
        result.width = imgWidth;
        result.height = imgHeight;
    } else {
        if (imgRatio >= defineRatio) {
            /* 图片极限 扁 */
            result.width = defineWidth;
            result.height = defineWidth / imgRatio;
        } else {
            /* 图片极限 长 */
            result.height = defineHeight;
            result.width = defineHeight * imgRatio;
        }
    }
    return result;
}

/** 常用web工具 */
export class WebUtils {
    /**
     * 获取url的search参数
     * @returns { [key: string]: string }
     */
    static urlSearchQuery = () => {
        let search = window.location.search;
        search = search.replace(/\?/, '');
        const arr1 = search.split('&');
        const query = {};
        arr1.forEach((v) => {
            const arr2 = v.split('=');
            const key = arr2[0];
            const value = arr2[1];
            query[key] = value;
        });
        return query;
    }
    /**
     * 获取url的search参数
     * @param {String} key 
     * @returns {String}
     * https://www.abc.com/index.html?a=1&b=2&c=3
     * urlQuery('a') => 1
     */
    static urlQuery = (key) => {
        const query = WebUtils.urlSearchQuery();
        const value = query[key] || '';
        return value;
    }

    /** 
     * 打印 
     * @param {String} msg 
     * @param {String} colorString
     * @param {Number} fontSize
     * */
    static print = (msg, colorString = '#111111', fontSize = 12) => {
        let color = '#111111';
        switch (colorString) {
            case 'r':
                color = '#ff0000';
                fontSize = 14;
                break;
            case 'g':
                color = '#009900';
                break;
            case 'b':
                color = '#0000ff';
                break;
            case '0':
                color = '#ff6600';
                break;
            default:
                break;
        }
        console.log(`%c${msg}`, `color:${color}; font-size:${fontSize}px;`);
    }

    /**  
     * 判定容器中文字内容的长度是否超出容器宽度 
     * @param {HTMLElement} container 
     * @param {String} fontSize 
     * @returns {Boolean}
     * */
    static checkTextOverflow = (container, fontSize = '14px') => {
        const containerWidth = container.offsetWidth; // 获取容器的宽度
        const text = container.innerText; // 获取容器中的文本
        const span = document.createElement('span'); // 创建一个临时的span元素

        span.style.visibility = 'hidden'; // 设置临时span元素的可见性为隐藏
        span.style.position = 'absolute'; // 设置位置为绝对，避免影响布局
        span.style.whiteSpace = 'nowrap'; // 设置不换行
        span.style.width = 'auto'; // 设置宽度自动
        span.style.fontSize = fontSize;
        document.body.appendChild(span); // 将临时span元素添加到文档中

        span.textContent = text; // 设置临时span元素的文本内容

        const textWidth = span.offsetWidth; // 获取文本内容的宽度

        document.body.removeChild(span); // 从文档中移除临时span元素
        // console.log(`textWidth:${textWidth}, containerWidth:${containerWidth}, text:${text}`);
        if (textWidth > containerWidth) {
            // 如果文本宽度大于容器宽度，则超出
            return true;
        } else {
            // 如果文本宽度小于或等于容器宽度，则没有超出
            return false;
        }
    }

    /** 
     * 复制文本，到剪切板 
     * @param {String} text 
     * */
    static copyText = async (text) => {
        let result = false;
        if ('clipboard' in navigator) {
            try {
                await navigator.clipboard.writeText(text);
                result = true;
            } catch (err) {
                result = false;
            }
        } else {
            result = false;
        }
        return Promise.resolve(result);
    }

    /** 
     * 异步加载js 
     * @param {String} scriptUrl 
     * @returns {Promise<void>}
     * */
    static loadScript = async (scriptUrl) => {
        const scriptElement = document.createElement("script");
        scriptElement.type = "text/javascript";
        scriptElement.src = scriptUrl;
        scriptElement.onload = () => {
            document.getElementsByTagName('body')[0].appendChild(scriptElement);
            return Promise.resolve(void 0);
        };
        scriptElement.onerror = (_error) => {
            console.log(`加载 ${scriptUrl} 失败`);
            return Promise.reject(void 0);
        };
    }
    /** 
     * 文件转换base64
     * @param {File} file
     * @returns {String}
     *  */
    static async readAsBase64(file) {
        return new Promise((resolve) => {
            const reader = new FileReader();
            // 当读取操作成功完成时触发
            reader.onload = function (e) {
                const base64Text = e.target.result; // 这是Base64编码的字符串
                if (typeof base64Text === 'string') {
                    resolve(base64Text);
                } else {
                    resolve(''); // 解决null的情况，或者可以reject一个错误
                }
            };
            // 将文件读取为Data URL（即Base64编码的字符串）
            reader.readAsDataURL(file);
        });

    }
    /** 
     * 文件下载 
     * @param {File} file
     * @param {String} fileName
     * */
    static downloadFile(file, fileName = '') {
        const a = document.createElement('a');
        a.href = URL.createObjectURL(file);
        a.download = fileName || file.name;
        a.click();
        URL.revokeObjectURL(a.href);
    }
    /** 
     * 文件地址转换为File 注意跨域 
     * @param {String} url
     * @param {String} fileName
     * @returns {Promise<File>}
     * */
    static async urlToFile(url, fileName = '') {
        const res = await fetch(url);
        const blob = await res.blob();
        const file = new File([blob], fileName || url.substring(url.lastIndexOf('/') + 1), {
            type: blob.type,
        });
        return file;
    }
    /**
     * 文件地址转换为 ArrayBuffer 注意跨域 
     * @param {String} url 
     * @returns ArrayBuffer
     */
    static async urlToArrayBuffer(url) {
        const res = await fetch(url);
        const arrayBuffer = await res.arrayBuffer();
        return arrayBuffer;
    };
    /**
     * 文件地址转换为Base64 注意跨域 
     * @param {String} url 
     * @returns {Promise<string>}
     */
    static async urlToBase64(url) {
        const res = await fetch(url);
        const blob = await res.blob();
        const reader = new FileReader();
        reader.readAsDataURL(blob);
        return new Promise((resolve, _reject) => {
            reader.onloadend = () => {
                const base64data = reader.result;
                resolve(base64data);
            };
        });
    };
    /** base64 => uint8Array */
    static base64ToUint8Array(base64) {
        // 移除 Base64 编码的前缀
        const base64WithoutPrefix = base64.split(',')[1];
        var raw = atob(base64WithoutPrefix);
        var uint8Array = new Uint8Array(raw.length);
        for (var i = 0; i < raw.length; i++) {
          uint8Array[i] = raw.charCodeAt(i);
        }
        return uint8Array;
      }
    /** 
     * 文件地址转换为blobUrl 注意跨域 
     * @param {String} url
     * @returns {Promise<string>}
     * */
    static async urlToBlobUrl(url) {
        const res = await fetch(url);
        const blob = await res.blob();
        const blobUrl = window.URL.createObjectURL(blob);
        return blobUrl;
    }
    /** 
     * 根据文件地址下载 
     * @param {String} url
     * @param {String} name
     * */
    static async downloadFileByUrl(url, name = '') {
        if (name) {
            const blobUrl = await FileUtils.urlToBlobUrl(url);
            const a = document.createElement('a');
            a.href = blobUrl;
            a.target = '_blank';
            a.download = name;
            a.click();
            URL.revokeObjectURL(a.href);
        } else {
            window.open(url);
        }
    }

    /** 错误图片 */
    static errorImage = "";


    /** 
     * src 转换 base64 
     * @param {String} src
     * @param {CutType} type 'none': 不压缩图片, screen:按照屏幕压缩, auto:根据图片尺寸压缩 
     * interface CutType {
            cut?: 'none' | 'screen' | 'auto';
            width?: number;
            height?: number;
            quality?: number;
        }
     * @returns {String}
     * */
    static srcToBase64(src, type) {
        const defaultType = { cut: 'auto', width: 1000, height: 1000, quality: 0.8 };
        const cutType = { ...defaultType, ...type };
        return new Promise((resolve) => {
            const img = new Image();
            /** 支持图片跨域 */
            img.crossOrigin = "Anonymous";
            img.src = src;

            img.onload = () => {
                let width = 1;
                let height = 1;
                const imgWidth = img.width;
                const imgHeight = img.height;

                switch (cutType.cut) {
                    case 'none':
                        width = img.width;
                        height = img.height;
                        break;
                    case 'screen':
                        const windowWidth = window.screen.width;
                        const windowHeight = window.screen.height;
                        const result1 = setSize(imgWidth, imgHeight, windowWidth, windowHeight);
                        width = result1.width;
                        height = result1.height;
                        break;
                    case 'auto':
                        const defineWidth = cutType.width;
                        const defineHeight = cutType.height;
                        const result2 = setSize(imgWidth, imgHeight, defineWidth, defineHeight);
                        width = result2.width;
                        height = result2.height;
                };
                const canvas = document.createElement("canvas");
                canvas.width = width;
                canvas.height = height;
                const ctx = canvas.getContext("2d");
                if (ctx) {
                    ctx.drawImage(img, 0, 0, width, height);
                    const base64 = canvas.toDataURL('image/jpeg', cutType.quality);
                    resolve(base64);
                } else {
                    resolve(ImageUtils.errorImage);
                }
            };
            img.onerror = () => {
                resolve(ImageUtils.errorImage);
            };
            img.src = src;

        });
    }

    /** 
     * image file 转换 base64 
     * @param {File} file
     * @param {CutType} type
     * @param {Promise<string>}
     * */
    static imageFileToBase64(file, type = {}) {
        const defaultType = { cut: 'auto', width: 1000, height: 1000, quality: 0.8 };
        const cutType = { ...defaultType, ...type };
        const src = URL.createObjectURL(file);
        return new Promise((resolve) => {
            ImageUtils.srcToBase64(src, cutType).then((base64) => {
                resolve(base64);
            });
        });
    }

    /** 是否是图片文件 */
    static isImageFile(file) {
        // 检查文件类型是否以'image/'开头
        return file.type.startsWith('image/');
    }

    /** 是否是图片文件名 */
    static isImageFileName(fileName) {
        const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp'];
        return imageExtensions.some(ext => fileName.toLowerCase().endsWith(ext));
    }

    /** base64 转换 url
     * @param {String} base64
     * @param {String} fileName
     * @returns { String } url
     */
    static downloadBase64(base64, fileName) {
        const base64Data = base64.replace(/^data:[\d|\D]+base64\,/i, '');
		const byteCharacters = atob(base64Data);
		const byteArrays = [];
		for (let offset = 0; offset < byteCharacters.length; offset += 512) {
			const slice = byteCharacters.slice(offset, offset + 512);
			const byteNumbers = new Array(slice.length);
			for (let i = 0; i < slice.length; i++) {
				byteNumbers[i] = slice.charCodeAt(i);
			}
			const byteArray = new Uint8Array(byteNumbers);
			byteArrays.push(byteArray);
		}
		const blob = new Blob(byteArrays, {
			type: 'application/octet-stream'
		});
		const url = URL.createObjectURL(blob);
		const link = document.createElement('a');
		link.href = url;
		link.download = fileName; 
		// 触发下载
		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link);
		// 释放URL对象
		URL.revokeObjectURL(url);
    }
}